import 'package:dio/dio.dart';
import 'package:flutterhouse/constants/index.dart';
import 'package:flutterhouse/utils/Emitter.dart';
import 'package:flutterhouse/utils/TokenManager.dart';

class DioRequest {
  final _dio = Dio();
  // 1.主构造函数
  DioRequest() {
    // 正常写法
    // 基础地址
    // _dio.options.baseUrl = GlobalVariable.BASE_URL;
    // // 连接超时时间
    // _dio.options.connectTimeout =
    //     const Duration(seconds: GlobalVariable.NEW_WORK_TIME_OUT);
    // // 接受超时时间
    // _dio.options.receiveTimeout =
    //     const Duration(seconds: GlobalVariable.NEW_WORK_TIME_OUT);
    // 链式写法
    _dio.options
      ..baseUrl = GlobalVariable.BASE_URL
      ..connectTimeout =
          const Duration(seconds: GlobalVariable.NEW_WORK_TIME_OUT)
      ..receiveTimeout =
          const Duration(seconds: GlobalVariable.NEW_WORK_TIME_OUT);
    // 添加拦截器
    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (context, handler) {
        // 请求拦截器
        // 注入token
        String token = tokenManager.getToken();
        if (token.isNotEmpty) {
          context.headers["Authorization"] = 'Bearer $token';
        }
        handler.next(context);
      },
      // 响应拦截器
      onResponse: (response, handler) {
        // 处理响应错误
        if (response.statusCode! >= 200 && response.statusCode! < 300) {
          // 响应成功
          handler.next(response);
        } else {
// 响应失败
          handler.reject(DioException(requestOptions: response.requestOptions));
        }
      },
      // 错误处理拦截器
      onError: (context, handler) async {
        // 判断状态码为401
        if (context.response!.statusCode == 401) {
          // 不行, 不能获取所需的上下文
          // Navigator.pushNamed(context, '/login');
          // 方案: 采用类似消息通知的方式
          // 1.获取refreshToken
          String refreshToken = tokenManager.getRefreshToken();
          if (refreshToken.isNotEmpty) {
            // 1.1调用接口刷新token
            try {
              await _refresh();
              // 1.2 能够到这里, 说明token已经刷新
              // 重新发起请求, 把之前的请求重新发一次(无感请求)
              return handler.resolve(await _dio.fetch(context.requestOptions));
            } on Exception catch (e) {
              // 1.2刷新失败, 跳转到登录页面
              eventBus.fire(LogoutEvent(e.toString()));
            }
          } else {
            // 1.3没有refreshToken, 跳转到登录页面
            eventBus.fire(LogoutEvent('401 未授权'));
          }
        }
        handler.reject(context);
      },
    ));
  }
// 调用接口去刷新token
  _refresh() async {
    // 1.获取refreshToken
    String refreshToken = tokenManager.getRefreshToken();
    // 2.发起请求
    Dio newDio = Dio();
    final res = await newDio.post(
      '${GlobalVariable.BASE_URL}${HTTP_PATH.REFRESH_TOKEN}',
      options: Options(
        headers: {
          "Authorization": 'Bearer $refreshToken',
        },
      ),
    );
    // 3. 获取新的token
    tokenManager.setToken(res.data['data']['token'],
        refreshToken: res.data['data']['refreshToken']);
  }

  // 2.定义请求方法
  get(String url, {Map<String, dynamic>? params}) {
    return _handleRes(_dio.get(url, queryParameters: params));
  }

  post(String url,
      {Map<String, dynamic>? params, required Map<String, dynamic> data}) {
    return _handleRes(_dio.post(url, data: data));
  }

  put(String url, {Map<String, dynamic>? data}) {
    return _handleRes(_dio.put(url, data: data));
  }

  delete(String url, {Map<String, dynamic>? params}) {
    return _handleRes(_dio.delete(url, queryParameters: params));
  }

// 上传
  upload(String url, {FormData? data}) {
    return _handleRes(_dio.post(url, data: data));
  }

  // 3.数据剥离
  _handleRes(Future<Response<dynamic>> task) async {
    final res = await task;

    if (res.data['code'] == GlobalVariable.SUCCESS_CODE) {
      return res.data['data'];
    }
    // 请求失败
    throw DioException(requestOptions: res.requestOptions);
  }
}

final DioRequest requestDio = DioRequest();
